#include "main_window.h"
#include "ui_main_window.h"

#include <QDebug>

#include <QFileDialog>
#include <QMessageBox>

#include "about_box.h"
#include "app_state_model.h"
#include "merged_texture_pack.h"
#include "pack_metadata.h"
#include "qvariant_utils.h"
#include "texture_pack.h"
#include "tile_sheet.h"
#include "tile.h"

#include "tile_table_delegate.h"
#include "tile_table_model.h"

MainWindow::MainWindow(AppStateModel* app_state, QWidget *parent)
    : QMainWindow(parent),
     app_state_model_(app_state),
     ui(new Ui::MainWindow) {
  ui->setupUi(this);

  const PackMetadata* metadata = app_state->packMetadata();
  connect(ui->table_view_, SIGNAL(doubleClicked(QModelIndex)),
          this, SLOT(chooseNextPack(QModelIndex)));
  connect(ui->file_list_, SIGNAL(currentTextChanged(QString)),
          this, SLOT(switchFiles(QString)));

  tile_delegate_ = new TileTableDelegate(this);
  connect(ui->background_color_button_, SIGNAL(colorChanged(QColor)),
          this, SLOT(setTableBackground(QColor)));

  foreach (QString tilesheet_path, metadata->tilesheetPaths()) {
    ui->file_list_->addItem(tilesheet_path);
  }
  ui->file_list_->setCurrentRow(0);
  ui->table_view_->setAppState(app_state_model_);
  ui->table_view_->setItemDelegate(tile_delegate_);
  ui->table_view_->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
  ui->table_view_->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
  setTableBackground(Qt::lightGray);
  ui->background_color_button_->setColor(Qt::lightGray);
  foreach (TexturePack* pack, *app_state->packs()) {
    ui->base_pack_combo_box_->addItem(pack->name(), QVariantPtr<TexturePack>::asVariant(pack));
  }
}

void MainWindow::showAboutBox() {
  AboutBox* box = new AboutBox();
  box->setAttribute(Qt::WA_DeleteOnClose);
  box->show();
}

void MainWindow::chooseTexturePackToAdd() {
  QString name_filter = tr("Minecraft texture packs (*.zip)",
                           "Name filter for texture packs in open dialog.");
// Qt will only use the native file dialog on Windows if we use the static getOpenFileName
// method, but on other platforms we'd really like to be window modal (and use a sheet on
// Mac OS X, for instance).
#ifdef Q_OS_WIN
  QString file_name = QFileDialog::getOpenFileName(this, QString(), QString(), name_filter);
  addTexturePack(file_name);
#else
  QFileDialog* dlg = new QFileDialog(this);
  dlg->setNameFilter(name_filter);
  dlg->open(this, SLOT(addTexturePack(QString)));
#endif
}

void MainWindow::addTexturePack(const QString& path) {
  QFileInfo info(path);
  TexturePack* pack =
      new TexturePack(info.fileName(), info, app_state_model_->defaultTexturePack(),
                      app_state_model_->packMetadata(), this);
  app_state_model_->addTexturePack(pack);
  ui->base_pack_combo_box_->addItem(pack->name(), QVariantPtr<TexturePack>::asVariant(pack));
}

void MainWindow::chooseSaveFilenameForMergedPack() {
  QString name_filter = tr("Minecraft texture packs (*.zip)",
                           "Name filter for texture packs in save dialog.");
// Qt will only use the native file dialog on Windows if we use the static getSaveFileName
// method, but on other platforms we'd really like to be window modal (and use a sheet on
// Mac OS X, for instance).
#ifdef Q_OS_WIN
  QString file_name = QFileDialog::getSaveFileName(this, QString(), QString(), name_filter);
  saveMergedTexturePack(file_name);
#else
  QFileDialog* dlg = new QFileDialog(this);
  dlg->setAcceptMode(QFileDialog::AcceptSave);
  dlg->setNameFilter(name_filter);
  dlg->open(this, SLOT(saveMergedTexturePack(QString)));
#endif
}

void MainWindow::setDefaultPack(int index) {
  TexturePack* pack =
      QVariantPtr<TexturePack>::asPointer(ui->base_pack_combo_box_->itemData(index));
  Q_ASSERT(pack);
  foreach (TileTableModel* model, tile_models_) {
    model->setDefaultPack(pack);
  }
}

void MainWindow::saveMergedTexturePack(const QString& file_name) {
  MergedTexturePack merged_pack;
  foreach (QString tilesheet_path, app_state_model_->packMetadata()->tilesheetPaths()) {
    TileTableModel* model = tileModelForTileSheet(tilesheet_path);
    QPixmap pixmap = model->tileSheetPixmap();
    merged_pack.addPixmap(tilesheet_path, pixmap);
  }
  if (!merged_pack.save(file_name)) {
    QMessageBox* box = new QMessageBox(this);
    box->setAttribute(Qt::WA_DeleteOnClose);
    box->setWindowTitle(QString("Save failed - %1").arg(qApp->applicationName()));
    box->setText(QString("The texture pack \"%1\" could not be saved.")
                 .arg(QDir::toNativeSeparators(file_name)));
    box->setInformativeText("If you are saving over an existing pack, make sure it is not open in "
                            "another program.  Also make sure you have permission to write to the "
                            "folder where you are saving the pack and that you have sufficient "
                            "disk space.  If all else fails, restart your computer and try again.");
    box->open();
  }
}

void MainWindow::chooseNextPack(QModelIndex index) {
  Q_ASSERT(current_tile_model_ != NULL);
  current_tile_model_->chooseNextPack(index);
}

void MainWindow::switchFiles(QString filename) {
  TileTableModel* tile_model = tileModelForTileSheet(filename);
  ui->table_view_->setModel(tile_model);
  current_tile_model_ = tile_model;
}

TileTableModel* MainWindow::tileModelForTileSheet(QString filename) {
  TileTableModel* tile_model = tile_models_.value(filename, NULL);
  if (!tile_model) {
    tile_model = new TileTableModel(app_state_model_, this);
    tile_model->setTileSheetName(filename);
    TexturePack* default_pack =
        QVariantPtr<TexturePack>::asPointer(
            ui->base_pack_combo_box_->itemData(ui->base_pack_combo_box_->currentIndex()));
    if (default_pack) {
      tile_model->setDefaultPack(default_pack);
    }
    tile_models_.insert(filename, tile_model);
  }
  return tile_model;
}

void MainWindow::setScaleFactor(int factor) {
  tile_delegate_->setScaleFactor(factor);
}

void MainWindow::setTableBackground(QColor color) {
  QPalette p = ui->table_view_->palette();
  p.setColor(QPalette::Base, color);
  ui->table_view_->setPalette(p);
}

MainWindow::~MainWindow() {
  delete ui;
}
